package pers.zifeng.distributed.lock.redis.service;

import lombok.extern.slf4j.Slf4j;
import pers.zifeng.distributed.lock.utils.PropertiesReader;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.params.SetParams;

import java.io.IOException;
import java.util.Collections;
import java.util.Properties;

/**
 * @author: zf
 * @date: 2021/06/22 16:59:46
 * @version: 1.0.0
 * @description: 提供redis服务
 */
@Slf4j
public class JedisLockService {

    private static Jedis jedis;
    private static final String LOCK_SUCCESS = "OK";
    private static final Long RELEASE_SUCCESS = 1L;

    static {
        try {
            Properties properties = PropertiesReader.getProperties("redis.properties");
            // 初始化
            String ip = properties.getProperty("ip");
            int port = Integer.parseInt(properties.getProperty("port"));
            int database = Integer.parseInt(properties.getProperty("database"));
            String password = properties.getProperty("password");

            jedis = new Jedis(ip, port);
            if (!password.isEmpty()) {
                jedis.auth(password);
            }
            jedis.select(database);
        } catch (IOException e) {
            log.error("初始化jedis失败！", e);
        }

    }

    public static void close() {
        jedis.close();
    }

    /**
     * 尝试获取分布式锁
     *
     * @param lockKey    锁
     * @param clientUUID 请求标识
     * @param expireTime 超期时间,单位：毫秒
     * @return 是否获取成功
     */
    public static boolean tryAndGetDistributedLock(String lockKey, String clientUUID, int expireTime) {

        // 设置nx(不存在才创建)，px(该key过期时间)
        SetParams setParams = new SetParams().nx().px(expireTime);
        String result = jedis.set(lockKey, clientUUID, setParams);

        return LOCK_SUCCESS.equals(result);
    }

    /**
     * 释放分布式锁
     *
     * @param lockKey    锁
     * @param clientUUID 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(String lockKey, String clientUUID) {

        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(clientUUID));

        return RELEASE_SUCCESS.equals(result);
    }

    /**
     * 往名为channelName的频道中发送消息
     *
     * @param channelName channel名称
     * @param message     消息
     */
    public static void publish(String channelName, String message) {
        jedis.publish(channelName, message);
    }

    /**
     * 订阅channel
     *
     * @param jedisPubSub jedisPubSub实例
     * @param channelName channel名称
     */
    public static void subscribe(JedisPubSub jedisPubSub, String channelName) {
        jedis.subscribe(jedisPubSub, channelName);
    }

}
